package com.example.myapp.models;

import com.example.myapp.event.EventHandler;
import com.example.myapp.event.StateMatrixChangeEvent;
import com.example.myapp.utils.StateAnalysis;

import java.util.List;

public class Game {

    private GameControl control;
    public static final int MATRIX_WIDTH = 8;

    private PieceView[] viewMatrix = new PieceView[MATRIX_WIDTH * MATRIX_WIDTH];
    private int[] stateMatrix = new int[MATRIX_WIDTH * MATRIX_WIDTH];

    public void initGame() {
        for (int i = 0; i < 8; i ++) {
            for (int j = 0; j < 8; j++) {
                PieceView newPieceView = new PieceView();
                newPieceView.setPiece(null);
                viewMatrix[i * MATRIX_WIDTH + j] = newPieceView;
                stateMatrix[i * MATRIX_WIDTH + j] = -1;
            }
        }

        setState(1, 3, 3);
        setState(1, 4, 3);
        setState(2, 3, 4);
        setState(2, 4, 4);

        StateMatrixChangeEvent event = new StateMatrixChangeEvent(this);
        EventHandler.handleEvent(event);
    }

    public void initFromStateMatrix(int[] mState) {
        initGame();
        stateMatrix = mState;
        for (int i = 0; i < MATRIX_WIDTH; i++) {
            for (int j = 0; j < MATRIX_WIDTH; j++) {
                viewMatrix[i * MATRIX_WIDTH + j].setPiece(new Piece());
                if (stateMatrix[i * MATRIX_WIDTH + j] != -1) {
                    viewMatrix[i * MATRIX_WIDTH + j].getPiece().setState(stateMatrix[i * MATRIX_WIDTH + j]);
                }
            }
        }

        StateMatrixChangeEvent event = new StateMatrixChangeEvent(this);
        EventHandler.handleEvent(event);
    }

    public void putPiece(int state, int x, int y) {
        //Assume [x, y] is empty
        PieceView touched = getAdjacentView(x, y, Direction.CENTER);

        if (touched == null) {
            //margin check failed, no action to take: do nothing
        } else if (touched.getPiece() != null) {
            //selected a cell not blanked, do nothing
        } else if (StateAnalysis.testFlip(this, state, x, y)) {
            setState(state, x, y);

            //try to flip
            List<int[]> flippablePoints = StateAnalysis.listAllFlippable(this, state, x, y);
            for (int[] f : flippablePoints) {
                //flip point
                setState(state, f[0], f[1]);
            }

            StateMatrixChangeEvent event = new StateMatrixChangeEvent(this);
            EventHandler.handleEvent(event);

            //TODO: to be simplified to this
//            EventHandler.fireDefaultEvent(StateMatrixChangeEvent.class, getInstance());
        }
    }

    private void setState(int state, int x, int y) {
        PieceView pieceView = viewMatrix[x * MATRIX_WIDTH + y];
        if (pieceView == null) {
            viewMatrix[x * MATRIX_WIDTH + y] = new PieceView();
            viewMatrix[x * MATRIX_WIDTH + y].setPiece(new Piece(state));
        } else if (pieceView.getPiece() == null) {
            pieceView.setPiece(new Piece(state));
        } else {
            pieceView.getPiece().setState(state);
        }

        stateMatrix[x * MATRIX_WIDTH + y] = state;
    }

    private PieceView getAdjacentView(int x, int y, Direction d) {
        if (x < 0 || y < 0 || x >= MATRIX_WIDTH || y >= MATRIX_WIDTH) {
            return null;
        }

        x += d.getDx();
        y += d.getDy();

        if (x < 0 || y < 0 || x >= MATRIX_WIDTH || y >= MATRIX_WIDTH) {
            return null;
        }

        return viewMatrix[x * MATRIX_WIDTH + y];
    }

    public int[] getStateMatrix() {
        return stateMatrix;
    }

    public GameControl getControl() {
        return control;
    }

    public void setControl(GameControl control) {
        this.control = control;
    }
}
